package ru.pb.game.data.zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.log4j.Logger;

/**
 * @author Felixx
 */
public class ZipDataCache
{
	private static final Logger _log = Logger.getLogger(ZipDataCache.class);
	private static ZipDataCache _instance;

	private Map<String, ZipData> _zipEntryes = new HashMap<String, ZipData>();
	private boolean _isClear = false;
	private boolean _isValid = false;

	public static ZipDataCache getInstance()
	{
		if(_instance == null)
		{
			_instance = new ZipDataCache();
		}
		return _instance;
	}

	private ZipDataCache()
	{
		load();

		_log.info("load " + _zipEntryes.size() + " entries.");
	}

	private void load()
	{

		File file = new File("./data.zip");
		if( !file.exists())
		{
			return;
		}

		try
		{
			ZipInputStream st = new ZipInputStream(new FileInputStream(file));

			ZipEntry entry = null;

			while((entry = st.getNextEntry()) != null)
			{
				if(entry.isDirectory())
				{
					continue;
				}

				int size = (int) entry.getSize();
				byte[] b = new byte[size];
				int rb = 0;
				int chunk = 0;

				while(size > rb)
				{
					chunk = st.read(b, rb, size - rb);
					if(chunk == -1)
					{
						break;
					}
					rb += chunk;
				}

				_zipEntryes.put(entry.getName(), new ZipData(entry.getName(), b));
			}
		}
		catch(IOException e)
		{
			_log.info("IOException: ZipDataCache.load(): " + e, e);
		}

		_isClear = false;
		_isValid = true;
	}

	public ZipData getFile(String fileName)
	{
		if( !_isValid)
		{
			throw new IllegalArgumentException("ZipDataCache is not valid.");
		}

		String needD = fileName.replace("./", "");
		if(_isClear)
		{
			load();
		}

		return _zipEntryes.get(needD);
	}

	public List<ZipData> getDirectory(String dirName)
	{
		if( !_isValid)
		{
			throw new IllegalArgumentException("ZipDataCache is not valid.");
		}

		if(_isClear)
		{
			load();
		}

		String needD = dirName.replace("./", "");
		List<ZipData> gstream = new ArrayList<ZipData>();

		for(Map.Entry<String, ZipData> entry : _zipEntryes.entrySet())
		{
			if(entry.getKey().startsWith(needD))
			{
				gstream.add(entry.getValue());
			}
		}

		return gstream;
	}

	public Set<Map.Entry<String, ZipData>> entrySet()
	{
		return _zipEntryes.entrySet();
	}

	public boolean hasDirEntry(String name)
	{
		if( !_isValid)
		{
			return false;
		}

		if(_isClear)
		{
			load();
		}

		for(ZipData d : _zipEntryes.values())
		{
			if(d.getName().startsWith(name.replace("./", "")))
			{
				return true;
			}
		}

		return false;
	}

	public boolean hasEntry(String name)
	{
		return _zipEntryes.containsKey(name.replace("./", ""));
	}

	public boolean isValid()
	{
		return _isValid;
	}

	public void clear()
	{
		for(ZipData d : _zipEntryes.values())
		{
			d.clear();
		}

		_zipEntryes.clear();

		_isClear = true;

		_log.info("entries cleared.");
	}
}
